package ru.volgogradetzzz.tween.easing {

	public class Elastic {
		public static function easeIn(time:uint, before:Number, change:Number, duration:uint, amplitude:Number = NaN, period:Number = NaN):Number {
			if (time == 0) {
				return before;
			}
			
			if (time >= duration) {
				return before + change;
			}  
			
			if (isNaN(period)) {
				period = duration * .3;
			}
			
			var elasticPeriod:Number;
			
			if (isNaN(amplitude) || amplitude < Math.abs(change)) { 
				amplitude = change; 
				elasticPeriod = period / 4; 
			} else {
				elasticPeriod = period / (2 * Math.PI) * Math.asin(change / amplitude);
			}
			
			var ratio:Number = time - 1;
			
			return -(amplitude * Math.pow(2, 10 * ratio) * Math.sin((ratio * duration - elasticPeriod) * (2 * Math.PI) / period)) + before;
		}
		
		public static function easeOut(time:uint, before:Number, change:Number, duration:uint, amplitude:Number = NaN, period:Number = NaN):Number {
			if (time == 0) {
				return before;
			}  
			
			if (time >= duration) {
				return before + change;
			}
			
			if (isNaN(period)) {
				period = duration * .3;
			}
			
			var elasticPeriod:Number;
			
			if (isNaN(amplitude) || amplitude < Math.abs(change)) { 
				amplitude = change; 
				elasticPeriod = period / 4; 
			} else { 
				elasticPeriod = period / (2 * Math.PI) * Math.asin(change / amplitude);
			}
			
			var ratio:Number = time / duration;
			
			return (amplitude * Math.pow(2, -10 * ratio) * Math.sin((ratio * duration - elasticPeriod) * (2 * Math.PI) / period) + change + before);
		}
		
		public static function easeInOut(time:uint, before:Number, change:Number, duration:uint, amplitude:Number = NaN, period:Number = NaN):Number {
			if (time == 0) {
				return before;
			}
			
			var ratio:Number = time / duration * 2;
			
			if (ratio >= 2) {
				return before + change;
			}  
			
			if (isNaN(period)) {
				period = duration * (.3 * 1.5);
			}
			
			var elasticPeriod:Number;
			
			if (isNaN(amplitude) || amplitude < Math.abs(change)) { 
				amplitude = change; 
				elasticPeriod = period / 4; 
			} else {
				elasticPeriod = period / (2 * Math.PI) * Math.asin(change / amplitude);
			}
			
			if (ratio < 1) {
				return -.5 * (amplitude * Math.pow(2, 10 * (ratio -= 1)) * Math.sin((ratio * duration - elasticPeriod) * (2 * Math.PI) / period)) + before;
			}
			
			return amplitude * Math.pow(2, -10 * (ratio -= 1)) * Math.sin((ratio * duration - elasticPeriod) * (2 * Math.PI) / period) * .5 + change + before;
		}		
	}
}
